/* main.c */

//TODO 类管理机制未完全完成
//TODO 虚拟机指令集有待补充
//TODO 需要设计类文件结构，或者兼容.class文件
//TODO 目前虚拟机指令集不兼容java，但是修改较为容易，目前仅为测试

#include <windows.h>

#define BAD_HANDLE(x) ((x == NULL) || (x == INVALID_HANDLE_VALUE))

LPVOID SvcAllocateMemory(DWORD dwSize){
    return malloc(dwSize);
}

BOOL SvcFreeMemory(LPVOID lpvMem){
    free(lpvMem);
    return TRUE;
}

LPVOID ServiceList[] = {
    // 0
    GetStdHandle,
    WriteFile,
    SetStdHandle,
    ReadFile,
    SvcAllocateMemory,//可以换成自定义函数以实现GC功能
    SvcFreeMemory,
    CreateFileW,
    DeleteFileW,
    socket,
    connect,
    // 10
    send,
    recv,
    sendto,
    recvfrom,
    bind,
    listen,
    accept,
    gethostname,
    gethostbyname,
    gethostbyaddr,
    // 20
    htons,
    ntohs,
    htonl,
    ntohl,
    GetCurrentProcess,
    GetCurrentThread,
    ExitProcess,
    ExitThread,
};

DWORD PrintError(LPSTR lpszLine, DWORD dwSize){
    static HANDLE hErr;
    DWORD dwWritten;
    hErr = GetStdHandle(STD_ERROR_HANDLE);
    WriteFile(hErr, lpszLine, dwSize, &dwWritten, NULL);
    return dwWritten;
}

inline void bswap_32(LPDWORD lpdwData){
    __asm__(
        "bswap %%eax"
    :"=a"(*lpdwData):"a"(*lpdwData));
}

/*
typedef struct{
    DWORD dwRelativeAddress;
    LPCSTR lpszName;
}METHOD, *PMETHOD;
*/

struct Class{
    LPVOID lpvCode;
    LPDWORD lpdwImport;
    LPVOID lpvStatic;
    LPCSTR lpszName;
};

struct Instance{
    LPVOID lpData;
    LPCSTR lpszClassName;
};

extern VOID __cdecl InterpreterEntry(const void* lpvEntry);

extern LPDWORD ImportFunctionTable;

struct Class LoadClass(LPCSTR lpszPath){
    HANDLE hOut;
    HANDLE hFile;
    LARGE_INTEGER Size;
    WORD wTitleSize;
    LPSTR lpszTitle;
    struct Class Result;

    hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    hFile = CreateFileA(
        lpszPath,
        GENERIC_READ,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );
    if(BAD_HANDLE(hFile)){
        WriteFile(hOut, "fatal error: Cannot open input file.\r\n", 38, NULL, NULL);
        ExitProcess(1);
    }
    GetFileSizeEx(hFile, &Size);
    Result.lpvCode = malloc(Size.LowPart);
    ReadFile(hFile, Result.lpvCode, Size.LowPart, NULL, NULL);
    Result.lpdwImport = NULL;
    Result.lpvStatic = NULL;
    wTitleSize = GetFileTitleA(lpszPath, NULL, 0);
    lpszTitle = malloc(wTitleSize + 1);
    lpszTitle[wTitleSize] = '\0';
    GetFileTitleA(lpszPath, lpszTitle, wTitleSize);
    Result.lpszName = lpszTitle;
    return Result;
}

int main(int argc, char** argv){
    HANDLE hOut;
    struct Class Start;

    hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if(argc != 2){
        WriteFile(hOut, "Usage: vm.exe [binfile]\r\n", 25, NULL, NULL);
        ExitProcess(1);
    }
    Start = LoadClass(argv[1]);
    InterpreterEntry(Start.lpvCode);
    return 0;
}
